﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.IO;
using System.Net;
using System.Windows.Forms;

using Biblio2.Configuration;

namespace Biblio2.OnlineParsing
{
    public class OnlineAPI
    {
        #region Const
        public const String m_sXmlNodeSerieName = "SeriesName";
        public const String m_sXmlNodeIdSerie = "seriesid";
        public const String m_sXmlNodeNameForEpisode = "Episode";
        public const String m_sXmlNodeEpisodeName = "SeriesName";
        public const String m_sXmlNodeIdEpisode = "seriesid";
        #endregion Const

        #region Singleton
        private static OnlineAPI m_instance = null;

        private OnlineAPI() 
        {
            m_listMirrors = new List<String>();
            m_sMirrorXml = String.Empty;
        }

        public static OnlineAPI GetInstance()
        {
            if (m_instance == null)
                m_instance = new OnlineAPI();

            return m_instance;
        }
        #endregion Singleton

        #region Attributs
        private List<String> m_listMirrors;
        private String m_sMirrorXml;
        
        #endregion

        #region Privée
        private XmlNodeList GetMirrorsList(String sServer)
        {
            String sUrl = sServer + "mirrors.xml";

            Stream data = RetrieveData(sUrl);

            if (data != null)
            {
                StreamReader reader = new StreamReader(data);
                String sXmlData = reader.ReadToEnd().Replace('\0', ' ');
                data.Close();
                reader.Close();
                try
                {
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(sXmlData);
                    XmlNode root = doc.FirstChild.NextSibling;
                    return root.ChildNodes;
                }
                catch (XmlException e)
                {
                    MessageBox.Show("Xml parsing of " + sUrl + " failed (line " + e.LineNumber + " - " + e.Message + ")", "XML Parsing error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            return null;
        }

        private bool LoadMirrorList()
        {
            XmlNodeList nodeList = GetMirrorsList(AppendAPI(ConfigurationManager.OnlineConfiguration.ServerAdress, true));

            if (nodeList == null)
                return false;
            int count = 0;
            foreach (XmlNode itemNode in nodeList)
            {
                foreach (XmlNode propertyNode in itemNode.ChildNodes)
                {
                    if (propertyNode.Name == "mirrorpath")
                        m_listMirrors.Add(propertyNode.InnerText);
                }
                count++;
            }
            return true;
        }

        public void SetRandomMirror()
        {
            if (m_listMirrors.Count == 0)
                LoadMirrorList();

            if ((m_sMirrorXml.Equals(String.Empty)) && (m_listMirrors.Count > 0))
            {
                Random r = new Random();
                m_sMirrorXml = m_listMirrors[r.Next(0, m_listMirrors.Count - 1)];
            }
        }

        private string AppendAPI(string path, bool appendKey)
        {
            return string.Format("{0}/api/{1}", path, appendKey ? (ConfigurationManager.OnlineConfiguration.ApiKey + "/") : string.Empty);
        }

        private Stream RetrieveTheData(String sUrl, bool enableErrorMsg)
        {
            if (sUrl == null || sUrl.Length < 1 || sUrl[0] == '/')
                // this happens if no active mirror is set
                return null;

            HttpWebRequest request = null;
            HttpWebResponse response = null;
            try
            {
                request = (HttpWebRequest)WebRequest.Create(sUrl);
                // Note: some network proxies require the useragent string to be set or they will deny the http request
                // this is true for instance for EVERY thailand internet connection (also needs to be set for banners/episodethumbs and any other http request we send)
                request.UserAgent = "Biblio";
                request.Timeout = 20000;

                response = (HttpWebResponse)request.GetResponse();

                if (response != null) // Get the stream associated with the response.
                    return response.GetResponseStream();
            }
            catch (Exception e)
            {
                // can't connect, timeout, etc
                if (enableErrorMsg)
                    MessageBox.Show("Can't connect to " + sUrl + " : " + e.Message, "Connection error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                throw e;
            }
            finally
            {
                // screws up the decompression
            }

            return null;
        }
        #endregion Privée

        #region Publique
        public static String GetMirror()
        {
            GetInstance().SetRandomMirror();
            return GetInstance().m_sMirrorXml;
        }

        public static Stream RetrieveData(String sUrl)
        {
            return GetInstance().RetrieveTheData(sUrl, true);
        }

        public static Stream RetrieveData(String sUrl, bool enableErrorMsg)
        {
            return GetInstance().RetrieveTheData(sUrl, enableErrorMsg);
        }
        #endregion Publique
    }
}

